{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Building footprint (plus street network) figure-ground diagrams\n",
    "\n",
    "Author: [Geoff Boeing](https://geoffboeing.com/)\n",
    "\n",
    "Use OSMnx to download OpenStreetMap building footprints and visualize them as figure-ground diagrams.\n",
    "\n",
    "  - [Documentation](https://osmnx.readthedocs.io/)\n",
    "  - [Journal article and citation info](https://doi.org/10.1111/gean.70009)\n",
    "  - [Code repository](https://github.com/gboeing/osmnx)\n",
    "  - [Examples gallery](https://github.com/gboeing/osmnx-examples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#!uv pip install --system --quiet osmnx[all]\n",
    "from pathlib import Path\n",
    "\n",
    "import osmnx as ox\n",
    "from IPython.display import Image\n",
    "\n",
    "ox.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# configure the inline image display\n",
    "img_folder = \"images\"\n",
    "extension = \"png\"\n",
    "size = 240\n",
    "\n",
    "# specify that we're retrieving building features from OSM\n",
    "tags = {\"building\": True}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building footprints within the city limits of Piedmont, California"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gdf = ox.features.features_from_place(\"Piedmont, California, USA\", tags)\n",
    "gdf_proj = ox.projection.project_gdf(gdf)\n",
    "fp = f\"./{img_folder}/piedmont_bldgs.{extension}\"\n",
    "fig, ax = ox.plot.plot_footprints(gdf_proj, filepath=fp, dpi=400, save=True, show=False, close=True)\n",
    "Image(fp, height=size, width=size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# save as a GeoPackage\n",
    "gdf_save = gdf.map(lambda x: str(x) if isinstance(x, list) else x)\n",
    "Path(\"data\").mkdir(parents=True, exist_ok=True)\n",
    "gdf_save.to_file(\"./data/piedmont_bldgs.gpkg\", driver=\"GPKG\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Now let's analyze the size of the building footprints..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# calculate the area in projected units (meters) of each building footprint, then display first five\n",
    "areas = gdf_proj.area\n",
    "areas.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# total area (sq m) covered by building footprints\n",
    "sum(areas)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get the total area within Piedmont's admin boundary in sq meters\n",
    "place = ox.geocoder.geocode_to_gdf(\"Piedmont, California, USA\")\n",
    "place_proj = ox.projection.project_gdf(place)\n",
    "place_proj.area.iloc[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# what proportion of piedmont is covered by building footprints?\n",
    "sum(areas) / place_proj.area.iloc[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## One and a half square kilometers near the Arc de Triomphe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "point = (48.873446, 2.294255)\n",
    "dist = 612\n",
    "gdf = ox.features.features_from_point(point, tags, dist=dist)\n",
    "gdf_proj = ox.projection.project_gdf(gdf)\n",
    "bbox = ox.utils_geo.bbox_from_point(point=point, dist=dist, project_utm=True)\n",
    "fp = f\"./{img_folder}/paris_bldgs.{extension}\"\n",
    "fig, ax = ox.plot.plot_footprints(\n",
    "    gdf_proj,\n",
    "    bbox=bbox,\n",
    "    color=\"w\",\n",
    "    filepath=fp,\n",
    "    dpi=90,\n",
    "    save=True,\n",
    "    show=False,\n",
    "    close=True,\n",
    ")\n",
    "Image(fp, height=size, width=size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Street network + building footprints: square-mile visualizations\n",
    "\n",
    "Plot and save to disk as .png"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# helper funcion to get one-square-mile street networks, building footprints, and plot them\n",
    "\n",
    "\n",
    "def make_plot(\n",
    "    place,\n",
    "    point,\n",
    "    network_type=\"drive\",\n",
    "    default_width=4,\n",
    "    street_widths=None,\n",
    "):\n",
    "    dpi = 40\n",
    "    dist = 805\n",
    "    fp = f\"./{img_folder}/{place}.{extension}\"\n",
    "\n",
    "    G = ox.graph.graph_from_point(\n",
    "        point,\n",
    "        dist=dist,\n",
    "        network_type=network_type,\n",
    "        truncate_by_edge=True,\n",
    "    )\n",
    "    gdf = ox.features.features_from_point(point, tags, dist=dist)\n",
    "    fig, ax = ox.plot.plot_figure_ground(\n",
    "        G=G,\n",
    "        dist=dist,\n",
    "        default_width=default_width,\n",
    "        street_widths=street_widths,\n",
    "        save=False,\n",
    "        show=False,\n",
    "        close=True,\n",
    "    )\n",
    "    fig, ax = ox.plot.plot_footprints(\n",
    "        gdf,\n",
    "        ax=ax,\n",
    "        filepath=fp,\n",
    "        dpi=dpi,\n",
    "        save=True,\n",
    "        show=False,\n",
    "        close=True,\n",
    "    )\n",
    "\n",
    "    return fp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "place = \"portland_buildings\"\n",
    "point = (45.517309, -122.682138)\n",
    "Image(make_plot(place, point), height=size, width=size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "place = \"richmond_district_buildings\"\n",
    "point = (37.781999, -122.472501)\n",
    "Image(make_plot(place, point), height=size, width=size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "place = \"port_au_prince_buildings\"\n",
    "point = (18.522240, -72.347607)\n",
    "fp = make_plot(place, point, network_type=\"all\", default_width=1, street_widths={\"secondary\": 3})\n",
    "Image(fp, height=size, width=size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "place = \"monrovia_liberia_buildings\"\n",
    "point = (6.340236, -10.747255)\n",
    "fp = make_plot(place, point, network_type=\"all\", default_width=2, street_widths={\"primary\": 6})\n",
    "Image(fp, height=size, width=size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
